package board;

import interfaces.Data;
import java.util.Random;

public class Board implements Data {

	int n; //wysokosc
	int m; //szerokosc
	int [][]board;
	protected int temp;
	public int x,y; //wspolrzedne 0
	protected int tmp;
	
	public Board(int _n, int _m)
	{
		n = _n;
		m = _m;
		int tmp=1;
		board = new int[n][m];
		for(int i=0; i!=n; ++i)
		{
			for(int j=0; j!=m; ++j)
			{
				board[i][j]=tmp;	
				tmp++;
			}
		}
		x=n-1;
		y=m-1;
		board[x][y]=0;
	}
	/**
	 * Funkcja mieszająca plansze losowa ilosc razy (od x do y) w losowych kierunkach
	 * zgodna z zalozeniami(dajaca sie rozwiazac).
	 */
	public void mix()
	{
		int x = 10; // losowanie od do
        int y = 500;
        int los;
        int b;
        Random r = new Random(); 
        int a=r.nextInt(y-x+1)+x;
        for(int i=0; i<a; ++i)
        {
        	los=0;
        	while(los==0)
        	{
	        	b = r.nextInt(4); //losowanie od 0 do 3 (up down left right)
	        	if(b==0 && canMove(Way.UP)){
	        		move2(Way.UP);
	        		los=1;
	        	}
	        	else if(b==1 && canMove(Way.DOWN)){
	        		move2(Way.DOWN);
	        		los=1;
	        	}
	        	else if(b==2 && canMove(Way.LEFT)){
	        		move2(Way.LEFT);
	        		los=1;
	        	}
	        	else if(b==3 && canMove(Way.RIGHT)){
	        		move2(Way.RIGHT);
	        		los=1;
	        	}
	        	else{
	        		b = r.nextInt(4);
	        	}
        	}
        	//wyswietl();
        }
	}
	public void wyswietl()
	{
		for(int i=0; i!=n; ++i)
		{
			for(int j=0; j!=m; ++j)
			{
				System.out.print(board[i][j]);
				System.out.print(" ");
			}
			System.out.println();
		}
		System.out.println();
	}
	/**
	 * Do przesuwania, ale nie tworzy nowego obiektu.
	 */
	public void move2(Board.Way way)
	{
		switch(way)
		{
			case UP: {temp=board[x-1][y]; board[x][y]=temp; x=x-1; board[x][y]=0;};
				break;
			case DOWN: {temp=board[x+1][y]; board[x][y]=temp; x=x+1; board[x][y]=0;};
				break;
			case LEFT: {temp=board[x][y-1]; board[x][y]=temp; y=y-1; board[x][y]=0;};
				break;
			case RIGHT:{temp=board[x][y+1]; board[x][y]=temp; y=y+1; board[x][y]=0;};
				break;
		}
	}
	public enum Way {
		UP, DOWN, LEFT, RIGHT;
	}
	
	@Override
	public int[][] getInOrder()
	{
		tmp=1;
		board = new int[n][m];
		for(int i=0; i!=n; ++i)
		{
			for(int j=0; j!=m; ++j)
			{
				board[i][j]=tmp;	
				tmp++;
			}
		}
		x=n-1;
		y=m-1;
		board[x][y]=0;
		return board;
	}
	@Override
	public boolean isDone() {
		tmp=1;
		for(int i=0; i!=n; ++i)
		{
			for(int j=0; j!=m; ++j)
			{
				if(tmp!=board[i][j]) 
					
				{	
					if(tmp==n*m) 
						return true;
					else
						return false;
				}
				tmp++;
			}
		}
		return true;
	}

	@Override
	public boolean isDone(Board data) 
	{
		return data.isDone();
	}

	@Override
	public boolean isTheSame(Board data) {
		// TODO Auto-generated method stub
			for(int i=0; i!=n; ++i)
			{
				for(int j=0; j!=m; ++j)
				{
					if(board[i][j]!=data.board[i][j]) return false;
				}
			}
			return true;
	}

	@Override
	public boolean isTheSame(Board data1, Board data2) {
		// TODO Auto-generated method stub
		return data1.isTheSame(data2);
	}
	@Override
	public Board move(Board.Way way) {
		Board tmp = new Board(n,m);
		tmp.x=x;
		tmp.y=y;  //wspolrzedne 0
		tmp.n=n;
		tmp.m=m;  // szer wysokosc plaszy
		for(int i=0; i!=n; ++i)  //przypisanie poszczegolnych elementow tablicy
		{
			for(int j=0; j!=m; ++j)
			{
				tmp.board[i][j]=board[i][j];
			}
		}
		//tu zmieniac tylko ten nowy obiekt tmp
		switch(way)
		{
			case UP: {temp=tmp.board[tmp.x-1][tmp.y]; tmp.board[x][y]=temp; tmp.x=tmp.x-1; tmp.board[tmp.x][tmp.y]=0;};
				break;
			case DOWN: {temp=tmp.board[tmp.x+1][tmp.y]; tmp.board[tmp.x][tmp.y]=temp; tmp.x=tmp.x+1; tmp.board[tmp.x][tmp.y]=0;};
				break;
			case LEFT: {temp=tmp.board[tmp.x][tmp.y-1]; tmp.board[tmp.x][tmp.y]=temp; tmp.y=tmp.y-1; tmp.board[tmp.x][tmp.y]=0;};
				break;
			case RIGHT:{temp=tmp.board[tmp.x][tmp.y+1]; tmp.board[tmp.x][tmp.y]=temp; tmp.y=tmp.y+1; tmp.board[tmp.x][tmp.y]=0;};
				break;
		}
		return tmp;
	}
	@Override
	public boolean canMove(Board.Way way) {
		// TODO Auto-generated method stub
		switch(way)
		{
			case UP: {if(x-1>=0) return true;};
				break;
			case DOWN: {if(x+1<n) return true;};
				break;
			case LEFT: {if(y-1>=0) return true;};
				break;
			case RIGHT:{if(y+1<m) return true;};
				break;
		}
		return false;
	}
	
	

	@Override
	public int getValue(int x, int y) throws BoardEx {
		// TODO Auto-generated method stub
		if(x>n) throw new BoardEx("Wyjscie poza tablice(wysokosc - x)");
		else if(x<0) throw new BoardEx("Wyjscie poza tablice ujemna wartosc indeksu x");
		else if(y>m) throw new BoardEx("Wyjscie poza tablice(szerokosc - y)");
		else if(y<0) throw new BoardEx("Wyjscie poza tablice ujemna wartosc indeksu y");
		return board[x][y];               //JEBNAC TU WYJATEK
	}

	@Override
	public int getWidth() {
		// TODO Auto-generated method stub
		return m;
	}

	@Override
	public int getHeight() {
		// TODO Auto-generated method stub
		return n;
	}

}
